#ifndef _GRAPHICS_H_
#define _GRAPHICS_H_

#include "common.h"
#include "math_2d.h"
#include "math_3d.h"
#include "colour.h"
#include "image.h"

////////////////////////////////////////////////////////////////////////////////

struct VertexType
{
  bool pos3;
  bool colour; 
  bool tex;
};

struct VertexP2C
{
  Vector2 pos;
  Colour colour;
  
  static VertexType type;
};

struct VertexP2T2
{
  Vector2 pos;
  Vector2 tex;
  
  static VertexType type;
};

////////////////////////////////////////////////////////////////////////////////

enum PrimitiveType
{
  PRIMITIVE_LINE,
  PRIMITIVE_LINE_LOOP,
  PRIMITIVE_TRIANGLES,
  PRIMITIVE_TRI_FAN,
};

struct Texture
{
  unsigned id;
};

struct Material
{
  Colour colour;
  bool alpha_blend;
  Texture texture;
};

struct VertexBuffer
{
  VertexType vertex_type;
  unsigned id;
  unsigned size;
  unsigned pos;
  char* buffer;
};

struct IndexBuffer
{
  unsigned id;
  unsigned size;
  unsigned pos;
  char* buffer;
};

struct VertexCache
{
  VertexType type;
  PrimitiveType primitive_type;
  Material material;
  VertexBuffer vertex_buffer;
  IndexBuffer index_buffer;
  bool mapped;
};

////////////////////////////////////////////////////////////////////////////////

void Graphics_init();
void Graphics_quit();

bool Graphics_setScreen(const char *caption, int width, int height, bool fullscreen, bool vSync);
const Dimension& Graphics_getScreenDim();

void Graphics_setClearColour(Colour colour);
void Graphics_clearScreen(bool colour, bool depth, bool stencil);
void Graphics_updateScreen();

void Graphics_beginDrawing();
void Graphics_endDrawing();

unsigned Graphics_getVertexSize(const VertexType& vertex_type);

void Graphics_createTexture(Texture* texture, const Image& image);
void Graphics_createTexture(Texture* texture, const ImageAlpha& image);
void Graphics_deleteTexture(Texture* texture);

void Graphics_initMaterial(Material* material);
void Graphics_setMaterial(const Material& material);
bool Graphics_cmpMaterials(const Material& m1, const Material& m2);

void Graphics_createVertexBuffer(VertexBuffer* vb, unsigned size);
void Graphics_deleteVertexBuffer(VertexBuffer* vb);
void Graphics_mapVertexBuffer(VertexBuffer* vb, const VertexType& vertex_type);
void Graphics_writeVertexBuffer(VertexBuffer* vb, unsigned length, const void* data);
void Graphics_unmapVertexBuffer(VertexBuffer* vb);
void Graphics_drawVertexBuffer(VertexBuffer* vb, unsigned offset, unsigned num);

void Graphics_createIndexBuffer(IndexBuffer* ib, unsigned size);
void Graphics_deleteIndexBuffer(IndexBuffer* ib);
void Graphics_mapIndexBuffer(IndexBuffer* ib);
void Graphics_writeIndexBuffer(IndexBuffer* ib, unsigned length, const void* data);
void Graphics_unmapIndexBuffer(IndexBuffer* ib);

void Graphics_pushOrthoView(float left, float right, float top, float bottom);
void Graphics_popView();

void Graphics_pushMatrix();
void Graphics_multMatrix(const Matrix3x2& m);
void Graphics_popMatrix();

void Graphics_drawBuffers(PrimitiveType primitive_type, VertexBuffer* vb,
  IndexBuffer* ib, unsigned offset, unsigned num);

void Graphics_createVertexCache(VertexCache* vc, unsigned vb_size,
  unsigned ib_size);
void Graphics_deleteVertexCache(VertexCache* vc);

void Graphics_draw(const VertexType& vertex_type, PrimitiveType primitive_type,
  const Material& material, unsigned num_vertices, const void* vertex,
  unsigned num_indices, const unsigned short* index);

#endif
